﻿using Abp.BackgroundJobs;
using Abp.Domain.Repositories;
using Abp.Domain.Services;
using Abp.Events.Bus;
using Abp.ObjectMapping;
using Abp.Runtime.Caching;
using Abp.Runtime.Validation;
using Abp.UI;
using AVIS.OutBound.AWD;
using AVIS.OutBound.CarGroups;
using AVIS.OutBound.CarGroups.Job;
using AVIS.OutBound.Orders.Cache;
using AVIS.OutBound.ORRegions;
using AVIS.OutBound.RateCodes;
using AVIS.OutBound.RateCodes.Cache;
using AVIS.OutBound.ThirdPartyService;
using AVIS.OutBound.Wizard;
using AVIS.OutBound.WizardAgent;
using Castle.Core.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AVIS.OutBound.Orders
{
    public class BookOrderManager : DomainService, IBookOrderManager
    {
        #region 构造函数
        public IEventBus EventBus { get; set; }

        private readonly ICacheManager _cacheManager;
        private readonly IObjectMapper _objectMapper;
        private readonly IAWDManager _AWDManager;
        private readonly IRateCodeManager _rateCodeMananger;
        private readonly ICarGroupManager _carGroupManager;
        private readonly WizardVehRetResAgent _wizardRetAgent;
        private readonly IOrderRepository _OrderRepository;
        private readonly IBackgroundJobManager _backgroundJobManager;
        private readonly IWizardManager _wizardManager;

        public BookOrderManager(ICacheManager cacheManager,
            IAWDManager awdManager,
            IObjectMapper objectMapper,
            IRateCodeManager RateCodeMananger,
            ICarGroupManager carGroupManager,
            IBackgroundJobManager backgroundJobManager,
            IOrderRepository OrderRepository,
            IWizardManager wizardManager)
        {
            _cacheManager = cacheManager;
            _AWDManager = awdManager;
            _objectMapper = objectMapper;
            _rateCodeMananger = RateCodeMananger;
            _carGroupManager = carGroupManager;
            _wizardRetAgent = new WizardVehRetResAgent();
            _OrderRepository = OrderRepository;
            _backgroundJobManager = backgroundJobManager;
            _wizardManager = wizardManager;

            EventBus = NullEventBus.Instance;
        }
        #endregion

        /// <summary>
        /// 保存预定到到缓存中
        /// </summary>
        /// <param name="order">预定单</param>
        /// <returns></returns>
        public BookOrderCacheItem SaveBookOrderCache(BookOrder order)
        {
            // 1. 需要从缓存中查询是否有OrderId，有需要将缓存数据获取出来，没有则为新的订单
            var bookOrderItem = GetBookOrderCacheOrNew(order.OrderId);

            // 2. 将提交的订单信息合并到预定单（BookOrderItem）中
            bookOrderItem.MapFrom(order);

            // 3. 如果SIPPCode和RateCode都不为空，则表示选中了车组，需要比较价格是否已经有变化了
            if (!string.IsNullOrEmpty(order.SIPPCode) && !string.IsNullOrEmpty(order.RateCode))
            {
                // 订单金额
                var CacheAmount = order.Amount;

                // 3.1 从Wizard接口中获取指定车组的信息（订单中包含SIPPCode和RateCode）
                var carGroup = _carGroupManager.GetCarGroup(_objectMapper.Map<AgentCarEquipmentRequest>(bookOrderItem));

                // 设置订单预付总金额和币种
                bookOrderItem.CarGroup = carGroup;
                bookOrderItem.Amount = carGroup.Price;
                bookOrderItem.CurrencyCode = carGroup.CurrencyCode;

                // 如果价格发送变化
                if (CacheAmount != bookOrderItem.Amount)
                {
                    // 3.2 触发预订单中的车组价格发生变化事件
                    EventBus.Trigger(new CarGroupPriceChangedEventData { OrderId = bookOrderItem.OrderId });

                    // 3.3 提醒用户价格变化了
                    throw new UserFriendlyException(string.Format("您选中车型组的价格已发生变化，从{0}变化到{1}，请刷新页面再试！", CacheAmount, carGroup.Price));
                }
            }

            // 4. 将预定单信息保存到BookOrderItem中
            SaveBookOrderInCache(bookOrderItem);

            // 5. 触发预定单信息保存完成事件.
            EventBus.Trigger(new BookOrderSaveCompletedEventData { OrderId = bookOrderItem.OrderId });

            return bookOrderItem;
        }

        /// <summary>
        /// 获取指定OrderId的预定单
        /// </summary>
        /// <param name="orderId">订单ID</param>
        /// <returns></returns>
        public BookOrder GetBookOrder(string orderId)
        {
            BookOrderCacheItem BookOrdeItem = null;
            //orderId不为空时，获取指定orderId的缓存
            if (!string.IsNullOrWhiteSpace(orderId))
            {
                BookOrdeItem = _cacheManager.GetBookOrderCache().GetOrDefault(orderId);
            }
            if (BookOrdeItem != null)
            {
                return _objectMapper.Map<BookOrder>(BookOrdeItem);
            }
            else
            {
                // 则提醒用户订单过期
                throw new UserFriendlyException(string.Format("指定的订单ID（{0}）不存在，可能订单已经过期！", orderId));
            }
        }

        /// <summary>
        /// 提交订单到Wizard接口并保持订单信息到数据库
        /// </summary>
        /// <param name="order">订单</param>
        /// <returns></returns>
        public Order SubmitOrder(Order order)
        {
            var isNew = string.IsNullOrEmpty(order.OrderNo);

            // 1. TODO 判断是否可以修改
            if (_OrderRepository.CanModifyOrder(order) == false)
            {
                throw new UserFriendlyException("该订单不支持修改！");
            }
            // 2. TODO 校验订单信息

            if (string.IsNullOrWhiteSpace(order.Telephone) || string.IsNullOrWhiteSpace(order.Email) || string.IsNullOrWhiteSpace(order.Surname))
            {
                throw new UserFriendlyException("客户信息有误，请检查手机，邮箱和客户的姓");
            }

            // 3. 通过Wizard接口提交订单信息
            var rs = _objectMapper.Map<SubmitOrderRequest>(order);
            var response = _wizardRetAgent.SubmitOrder(rs);
            _wizardManager.HandleErrorMessage(response); // 处理Wizard结果的错误信息

            // 保存到数据库
            order.OrderNo = response.Data.OrderNo;
            order.CurrencyCode = response.Data.CurrencyCode;
            order.Amount = response.Data.QuotedTMI;
            ///获取真实的AWD
            var awd = _AWDManager.GetRealAWDCode(order.AWD);
            if (!string.IsNullOrWhiteSpace(awd))
            {
                order.AWD = awd;
            }
            _OrderRepository.SaveOrder(order);

            order.IsSubmit = true; // 设置订单已经提交

            // TODO 发送邮件和短信
            //try
            //{
            //    _NotifyAppService.SendOrderSuccessMail(order.Customer.Email, order.GetOrderSuccessMailParameters(_AWDAppService.GetRealAWDCode(order.AWD)));
            //    _NotifyAppService.SendOrderSuccessMessage(order.Customer.Telephone, isNew, order.GetOrderSuccessMessageParameters());
            //}
            //catch (Exception ex)
            //{
            //    LogWriter.Error(ex, string.Format("订单（{0},{1}）发送邮件或短信出错了！", order.OrderNo, order.Customer.Surname));
            //}

            // 记录日志
            //LogWriter.InfoFormat("订单信息（{0},{1}）提交成功。<BR />{2}",
            //    order.OrderNo, order.Customer.Surname, Newtonsoft.Json.JsonConvert.SerializeObject(order));


            return order;
        }

        /// <summary>
        /// 取消订单，通过Wizard接口取消并修改数据库的订单信息，最后发送订单取消事件
        /// </summary>
        /// <param name="order">订单</param>
        /// <returns></returns>
        public CancelOrderOutput CancelOrder(AgentCancelOrderRequest request)
        {
            // 通过Wizard接口取消订单
            var rs = _objectMapper.Map<CancelOrderRequest>(request);
            var response = _wizardRetAgent.CancelOrder(rs);
            _wizardManager.HandleErrorMessage(response); // 处理Wizard结果的错误信息

            var data = ToOutput(response);

            // 更新数据库
            _OrderRepository.CancelOrder(request.OrderNo, request.Surname, request.CancelReason);

            // TODO 发送取消订单的邮件和短信
            //var templateParameters = order.Customer.Firstname + " " + order.Customer.Surname + " " + order.Customer.Surname + OBConstant.SysSeparator;
            //templateParameters += order.OrderNo + OBConstant.SysSeparator;
            //templateParameters += order.PickupDateTime.ToString("dddd", new System.Globalization.CultureInfo("zh-cn")) + "," + order.PickupDateTime.ToString("yyyy年MM月dd日 HH:mm:ss") + OBConstant.SysSeparator;
            //templateParameters += order.ReturnDateTime.ToString("dddd", new System.Globalization.CultureInfo("zh-cn")) + "," + order.ReturnDateTime.ToString("yyyy年MM月dd日 HH:mm:ss") + OBConstant.SysSeparator;
            //templateParameters += order.PickUpStore.CNName + order.PickUpStore.LocationAddress + OBConstant.SysSeparator;
            //templateParameters += order.ReturnStore.CNName + order.ReturnStore.LocationAddress + OBConstant.SysSeparator;
            //templateParameters += order.CarGroup.ModelName + OBConstant.SysSeparator;
            //_NotifyAppService.SendCancelOrderMail(order.Customer.Email, templateParameters);

            //_NotifyAppService.SendCancelOrderMessage(order.Customer.Telephone, order.OrderNo);

            // TODO 取消第三方订单
            var thirdAgent = new ThirdAgentService();
            thirdAgent.CancelYouYouOrder(request.OrderNo, "系统自动取消，原因：AVIS订单已取消。");
            thirdAgent.CancelAAOrder(request.OrderNo, Abp.Timing.Clock.Now, "1");

            return data;
        }

        #region 私有方法
        /// <summary>
        /// 将预定单保存到缓存中
        /// </summary>
        /// <param name="cacheItem">预定单</param>
        private void SaveBookOrderInCache(BookOrderCacheItem cacheItem)
        {
            if (cacheItem.IsVaild())
            {
                Logger.Debug(string.Format("预订单对象（{0}）的结果体：{1}", cacheItem.OrderId, Newtonsoft.Json.JsonConvert.SerializeObject(cacheItem)));

                _cacheManager.GetBookOrderCache().Set(cacheItem.OrderId, cacheItem);
            }
        }

        /// <summary>
        /// 获取缓存中的订单对象，如果没有就创建一个空的预定单对象
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        private BookOrderCacheItem GetBookOrderCacheOrNew(string orderId)
        {
            var cache = _cacheManager.GetBookOrderCache();
            BookOrderCacheItem bookOrderItem = null;
            if (string.IsNullOrWhiteSpace(orderId))
            {
                bookOrderItem = new BookOrderCacheItem
                {
                    OrderId = Guid.NewGuid().ToString(),
                    BookingDate = Abp.Timing.Clock.Now,
                };
            }
            else
            {
                // 获取指定orderId的缓存数据
                bookOrderItem = cache.Get(orderId,
                    (key) =>
                    {
                        return new BookOrderCacheItem
                        {
                            OrderId = Guid.NewGuid().ToString(),
                            BookingDate = Abp.Timing.Clock.Now,
                        };
                    });
            }

            return bookOrderItem;
        }

        /// <summary>
        /// 查询订单
        /// </summary>
        /// <param name="OrderNo"></param>
        /// <param name="Surname"></param>
        /// <returns></returns>
        public Order QueryOrder(string orderNo, string surname)
        {
            // 1. 从获取Wizard获取订单数据
            var request = new OrderQueryRequest { ReservationNumber = orderNo, Surname = surname };
            var response = _wizardRetAgent.OrderQuery(request);
            _wizardManager.HandleErrorMessage(response); // 处理Wizard结果的错误信息

            // 2. 获取数据库中的订单数据
            //var dbOrder = _OrderRepository.GetOrder(orderNo, surname);
            var data = _cacheManager.GetOrderCache().Get(orderNo, f => GetOrder(orderNo, surname));
            var dbOrder = _objectMapper.Map<Order>(data);
            // 3. 合并Wizard接口的订单和数据库的订单信息
            var order = MergeOrderInfo(response.Data, dbOrder);

            return order;
        }

        private OrderCacheItem GetOrder(string orderNo, string surname)
        {
            var dbOrder = _OrderRepository.GetOrder(orderNo, surname);
            var data = _objectMapper.Map<OrderCacheItem>(dbOrder);
            return data;
        }



        /// <summary>
        /// 合并Wizard接口的订单和数据库的订单信息
        /// </summary>
        /// <param name="response"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        private Order MergeOrderInfo(OrderQueryDto dto, Order dbOrder)
        {
            var order = dbOrder ?? new Order // DB中没有订单信息，可能是从其他途径下的订单
            {
                OrderId = Guid.NewGuid().ToString(),
                BookingDate = Abp.Timing.Clock.Now,
                OrderStep = 6,
                IATA = "",
                IATAType = 5,
                PayType = "2",
            };

            if (!string.IsNullOrWhiteSpace(dto.Firstname) && dto.Firstname != order.Firstname)
            {
                order.Firstname = dto.Firstname;
            }
            if (!string.IsNullOrWhiteSpace(dto.Surname) && dto.Surname != order.Surname)
            {
                order.Surname = dto.Surname;
            }

            if (!string.IsNullOrWhiteSpace(dto.CurrencyCode) && dto.CurrencyCode != order.CurrencyCode)
            {
                order.CurrencyCode = dto.CurrencyCode;
            }

            if (!string.IsNullOrWhiteSpace(dto.OrderNo) && dto.OrderNo != order.OrderNo)
            {
                order.OrderNo = dto.OrderNo;
            }

            if (dto.PickupDateTime.Ticks > 0 && dto.PickupDateTime != order.PickupDateTime)
            {
                order.PickupDateTime = dto.PickupDateTime;
            }

            if (dto.ReturnDateTime.Ticks > 0 && dto.ReturnDateTime != order.ReturnDateTime)
            {
                order.ReturnDateTime = dto.ReturnDateTime;
            }

            if (!string.IsNullOrWhiteSpace(dto.PickUpStoreCode) && dto.PickUpStoreCode != order.PickUpStoreCode)
            {
                order.PickUpStoreCode = dto.PickUpStoreCode;
            }

            if (!string.IsNullOrWhiteSpace(dto.ReturnStoreCode) && dto.ReturnStoreCode != order.ReturnStoreCode)
            {
                order.ReturnStoreCode = dto.ReturnStoreCode;
            }

            if (dto.QuotedTMI > 0 && dto.QuotedTMI != order.Amount)
            {
                order.Amount = dto.QuotedTMI;
            }

            if (!string.IsNullOrWhiteSpace(dto.RateCode) && dto.RateCode != order.RateCode)
            {
                order.RateCode = dto.RateCode;
            }

            if (!string.IsNullOrWhiteSpace(dto.SIPPCode) && dto.SIPPCode != order.SIPPCode)
            {
                order.SIPPCode = dto.SIPPCode;
            }

            order.RentalLength = int.Parse(dto.CarGroup.RentalLength);

            var rentalUnit = dto.CarGroup.RentalUnit.ToLower() == "day" ? "天" : dto.CarGroup.RentalUnit;
            if (!string.IsNullOrWhiteSpace(rentalUnit) && rentalUnit != order.RentalUnit)
            {
                order.RentalUnit = rentalUnit;
            }

            if (dto.CouponDiscountAmount > 0 && dto.CouponDiscountAmount != order.CouponDiscountAmount)
            {
                order.CouponDiscountAmount = dto.CouponDiscountAmount;
            }
            if (!string.IsNullOrWhiteSpace(dto.CouponDiscountCurrencyCode) && dto.CouponDiscountCurrencyCode != order.CouponDiscountCurrencyCode)
            {
                order.CouponDiscountCurrencyCode = dto.CouponDiscountCurrencyCode;
            }

            var awd = string.IsNullOrWhiteSpace(dto.AWD) ? order.AWD : dto.AWD;
            order.AWD = _AWDManager.GetCNAWDCode(awd);

            // 合并车组信息
            order.CarGroup = ConvertDtoToCarGroup(dto.CarGroup, order.CarGroup);

            return order;
        }

        /// <summary>
        /// 合并Wizard查询订单接口的车组信息和数据库的车组信息
        /// </summary>
        /// <returns></returns>
        private CarGroup ConvertDtoToCarGroup(CarGroupDto dto, CarGroup dbCarGroup)
        {
            var carGroup = dbCarGroup ?? new CarGroup();

            if (!string.IsNullOrWhiteSpace(dto.ModelName) && dto.ModelName != carGroup.ModelName)
            {
                carGroup.ModelName = dto.ModelName;
            }

            var modelCode = dto.ModelName.Substring(6, 2).Trim();
            if (!string.IsNullOrWhiteSpace(modelCode) && modelCode != carGroup.ModelCode)
            {
                carGroup.ModelCode = modelCode;
            }

            if (!string.IsNullOrWhiteSpace(dto.SIPPCode) && dto.SIPPCode != carGroup.SIPPCode)
            {
                carGroup.SIPPCode = dto.SIPPCode;
            }

            if (dto.Price > 0 && dto.Price != carGroup.Price)
            {
                carGroup.Price = dto.Price;
            }

            if (!string.IsNullOrWhiteSpace(dto.CurrencyCode) && dto.CurrencyCode != carGroup.CurrencyCode)
            {
                carGroup.CurrencyCode = dto.CurrencyCode;
            }

            if (!string.IsNullOrWhiteSpace(dto.PictureURL) && !carGroup.PictureURL.Contains(dto.PictureURL))
            {
                carGroup.PictureURL = dto.PictureURL;
            }

            if (!string.IsNullOrWhiteSpace(dto.RateCode) && dto.RateCode != carGroup.RateCode)
            {
                carGroup.RateCode = dto.RateCode;
            }

            if (dto.Feature != null)
            {
                if (!string.IsNullOrWhiteSpace(dto.Feature.Category))
                {
                    carGroup.Feature.Category = dto.Feature.Category;
                }

                if (!string.IsNullOrWhiteSpace(dto.Feature.Doors))
                {
                    carGroup.Feature.Doors = dto.Feature.Doors;
                }

                if (dto.Feature.HasAirConditioning.HasValue)
                {
                    carGroup.Feature.HasAirConditioning = dto.Feature.HasAirConditioning.Value;
                }

                if (dto.Feature.IsAutomatic.HasValue)
                {
                    carGroup.Feature.IsAutomatic = dto.Feature.IsAutomatic.Value;
                }

                if (!string.IsNullOrWhiteSpace(dto.Feature.Seats))
                {
                    carGroup.Feature.Seats = dto.Feature.Seats;
                }

                if (!string.IsNullOrWhiteSpace(dto.Feature.Suitcases))
                {
                    carGroup.Feature.Suitcases = dto.Feature.Suitcases;
                }

                if (!string.IsNullOrWhiteSpace(dto.Feature.FeaturesString))
                {
                    carGroup.Feature.FeaturesString = dto.Feature.FeaturesString;
                }
            }

            if (dto.PriceInclue.Coverages.Count > 0
                && dto.PriceInclue.Coverages.Count != carGroup.PriceInclue.Coverages.Count)
            {
                carGroup.PriceInclue.Coverages = dto.PriceInclue.Coverages.Select(c =>
                    new PriceIncludeCoverage { Code = c.Code, Content = c.Content }).ToList();
            }

            if (dto.PriceInclue.VehicleCharges.Count > 0
                && dto.PriceInclue.VehicleCharges.Count != carGroup.PriceInclue.VehicleCharges.Count)
            {
                carGroup.PriceInclue.VehicleCharges = dto.PriceInclue.VehicleCharges;
            }

            var distance = dto.PriceInclue.Distance;
            if (distance != null)
            {
                carGroup.PriceInclue.Distance = new PriceIncludeDistance
                {
                    DistanceUnit = distance.DistanceUnit,
                    PeriodUnit = distance.PeriodUnit,
                    Quantity = distance.Quantity,
                    Unlimited = distance.Unlimited,
                };
            }

            // 合并增值服务
            foreach (var equip in dto.CarEquipments)
            {
                var oldEquip = carGroup.CarEquipments.FirstOrDefault(e => e.Type == equip.Type);
                if (oldEquip == null)
                {
                    // TODO 需要考虑如何处理增值服务
                    // carGroup.CarEquipments.Add(equip);
                }
                else
                {
                    if (!string.IsNullOrEmpty(equip.Type) && oldEquip.Type != equip.Type)
                    {
                        oldEquip.Type = equip.Type;
                    }

                    if (!string.IsNullOrEmpty(equip.Amount) && oldEquip.Amount != equip.Amount)
                    {
                        oldEquip.Amount = equip.Amount;
                    }

                    if (equip.Quantity > 0 && oldEquip.Quantity != equip.Quantity)
                    {
                        oldEquip.Quantity = equip.Quantity;
                    }

                    if (!string.IsNullOrEmpty(equip.CurrencyCode) && oldEquip.CurrencyCode != equip.CurrencyCode)
                    {
                        oldEquip.CurrencyCode = equip.CurrencyCode;
                    }
                    
                    if (!string.IsNullOrEmpty(equip.UnitName) && oldEquip.UnitName != equip.UnitName)
                    {
                        oldEquip.UnitName = equip.UnitName;
                    }
                    if (!string.IsNullOrEmpty(equip.UnitPrice) && oldEquip.UnitPrice != equip.UnitPrice)
                    {
                        oldEquip.UnitPrice = equip.UnitPrice;
                    }
                }
            }

            return carGroup;
        }


        private CancelOrderOutput ToOutput(CancelOrderResponse response)
        {
            var output = new CancelOrderOutput();
            HandleErrorMessage(response, output);

            output.Result = response.Data;
            return output;
        }


        //private OrderOutput ToOrder(SubmitOrderResponse response)
        //{
        //    var output = new OrderOutput();
        //    HandleErrorMessage(response, output);
        //    var dto = response.Data;

        //    var bookOrder = new BookOrder();
        //    bookOrder.OrderNo = dto.OrderNo;
        //    bookOrder.Amount = dto.QuotedTMI;
        //    bookOrder.CurrencyCode = dto.CurrencyCode;
        //    output.Order = bookOrder;
        //    return output;
        //}

        /// <summary>
        /// 处理错误信息
        /// </summary>
        /// <param name="response"></param>
        /// <param name="outputDto"></param>
        private void HandleErrorMessage(IResponse response, IOutputDTO outputDto)
        {
            // 处理提醒信息
            if (response.WarningCode != 0 || !string.IsNullOrWhiteSpace(response.WarningMessage))
            {
                // 转换为中文的错误信息
                var warningMsg = _wizardManager.GetErrorMessage(response.WarningCode.ToString());
                outputDto.WarningMessage = warningMsg != null ? warningMsg.CNErrorElement : response.WarningMessage;
            }

            // 处理错误信息
            if (response.ErrorCode != 0)
            {
                // 转换为中文的错误信息
                var errorMsg = _wizardManager.GetErrorMessage(response.ErrorCode.ToString());
                outputDto.ErrorMessage = errorMsg != null ? errorMsg.CNErrorElement : response.ErrorMessage;
                var strErrorMsg = errorMsg != null ? errorMsg.CNErrorElement : response.ErrorMessage;
                if (response is CarEquipmentResponse)  // 如果是增值服务，则需要刷新界面并会清空缓存XML
                {
                    throw new UserFriendlyException(strErrorMsg + " 稍后尝试为您重新请求");
                }
                else
                {
                    throw new UserFriendlyException(strErrorMsg);
                }
            }
            if (!string.IsNullOrWhiteSpace(response.ErrorMessage))
            {
                outputDto.ErrorMessage = response.ErrorMessage;
                throw new UserFriendlyException(response.ErrorMessage);
            }
        }

        #endregion
    }
}
